रस्ट का स्वामित्व और उधारी भ्रमित करने वाली हो सकती है यदि हम यह नहीं समझ पाते हैं कि वास्तव में क्या हो रहा है। यह विशेष रूप से सच है जब पहले से सीखी गई प्रोग्रामिंग शैली को एक नए प्रतिमान में लागू किया जाता है; हम इसे एक प्रतिमान बदलाव कहते हैं। स्वामित्व एक नया विचार है, फिर भी पहली बार में समझना मुश्किल है, लेकिन जितना अधिक हम इस पर काम करते हैं, यह आसान हो जाता है। इससे पहले कि हम रस्ट के स्वामित्व और उधार के बारे में आगे बढ़ें, आइए पहले समझते हैं कि "मेमोरी सेफ्टी" और "मेमोरी लीक" क्या हैं और प्रोग्रामिंग भाषाएं उनसे कैसे निपटती हैं। मेमोरी सेफ्टी क्या है? मेमोरी सेफ्टी एक सॉफ्टवेयर एप्लिकेशन की स्थिति को संदर्भित करता है जहां मेमोरी पॉइंटर्स या संदर्भ हमेशा वैध मेमोरी को संदर्भित करते हैं। चूंकि स्मृति भ्रष्टाचार एक संभावना है, इसलिए प्रोग्राम के व्यवहार के बारे में बहुत कम गारंटी है यदि यह स्मृति सुरक्षित नहीं है। सीधे शब्दों में कहें, यदि कोई प्रोग्राम वास्तव में मेमोरी सुरक्षित नहीं है, तो इसकी कार्यक्षमता के बारे में कुछ आश्वासन हैं। मेमोरी-असुरक्षित प्रोग्राम के साथ काम करते समय, एक दुर्भावनापूर्ण पार्टी किसी अन्य की मशीन पर रहस्यों को पढ़ने या मनमाने कोड को निष्पादित करने के लिए दोष का उपयोग करने में सक्षम होती है। आइए एक स्यूडोकोड का उपयोग करके देखें कि वैध मेमोरी क्या है। // pseudocode #1 - shows valid reference { // scope starts here int x = 5 int y = &x } // scope ends here उपरोक्त छद्म कोड में, हमने के मान के साथ असाइन किया गया एक चर बनाया है। हम संदर्भ बनाने के लिए ऑपरेटर या कीवर्ड का उपयोग करते हैं। इस प्रकार, सिंटैक्स हमें एक संदर्भ बनाने देता है जो के मान को संदर्भित करता है। सीधे शब्दों में कहें तो, हमने एक वैरिएबल बनाया है जो का मालिक है और एक वेरिएबल जो कि का संदर्भ है। 10 x & &x x x 5 y x चूंकि दोनों चर और एक ही ब्लॉक या दायरे में हैं, चर का एक वैध संदर्भ है जो के मान को संदर्भित करता है। परिणामस्वरूप, चर का मान है। x y y x y 5 नीचे दिए गए स्यूडोकोड पर एक नज़र डालें। जैसा कि हम देख सकते हैं, का दायरा उस ब्लॉक तक सीमित है जिसमें इसे बनाया गया है। जब हम को इसके दायरे से बाहर एक्सेस करने का प्रयास करते हैं तो हम झूलने वाले संदर्भों में आ जाते हैं। लटकता हुआ संदर्भ ...? आख़िर यह क्या है? x x // pseudocode #2 - shows invalid reference aka dangling reference { // scope starts here int x = 5 } // scope ends here int y = &x // can't access x from here; creates dangling reference लटकता हुआ संदर्भ एक लटकता हुआ संदर्भ एक सूचक है जो एक स्मृति स्थान को इंगित करता है जो किसी और को दिया गया है या जारी किया गया है (मुक्त)। यदि कोई प्रोग्राम (उर्फ ) स्मृति को संदर्भित करता है जिसे जारी किया गया है या मिटा दिया गया है, तो यह क्रैश हो सकता है या गैर-निर्धारक परिणाम उत्पन्न कर सकता है। प्रक्रिया ऐसा कहने के बाद, कुछ प्रोग्रामिंग भाषाओं की एक संपत्ति है जो प्रोग्रामर को अमान्य डेटा से निपटने की अनुमति देती है। नतीजतन, स्मृति असुरक्षितता ने कई तरह की समस्याएं पेश कीं जो निम्नलिखित प्रमुख सुरक्षा कमजोरियों का कारण बन सकती हैं: स्मृति असुरक्षितता आउट-ऑफ-बाउंड पढ़ता है आउट-ऑफ-बाउंड लिखता है का उपयोग के बाद नि: शुल्क स्मृति असुरक्षितता के कारण होने वाली भेद्यताएं कई अन्य गंभीर सुरक्षा खतरों की जड़ में हैं। दुर्भाग्य से, इन कमजोरियों को उजागर करना डेवलपर्स के लिए बेहद चुनौतीपूर्ण हो सकता है। मेमोरी लीक क्या है? यह समझना महत्वपूर्ण है कि मेमोरी लीक क्या है और इसके परिणाम क्या हैं। एक स्मृति खपत का एक अनजाने रूप है जिससे डेवलपर स्मृति के आवंटित ब्लॉक को मुक्त करने में विफल रहता है जब इसकी आवश्यकता नहीं होती है। यह स्मृति सुरक्षा के बिल्कुल विपरीत है। विभिन्न मेमोरी प्रकारों के बारे में बाद में, लेकिन अभी के लिए, बस यह जान लें कि एक निश्चित-लंबाई वाले चर को संकलित समय पर संग्रहीत करता है, जबकि चर का आकार जो बाद में रनटाइम पर बदल सकता है, उसे पर रखा जाना चाहिए। स्मृति रिसाव ढेर स्टैक ढेर हीप मेमोरी आवंटन की तुलना में, स्टैक मेमोरी आवंटन को सुरक्षित माना जाता है क्योंकि मेमोरी स्वचालित रूप से रिलीज़ हो जाती है जब यह अब प्रासंगिक या आवश्यक नहीं है, या तो प्रोग्रामर द्वारा या प्रोग्राम-रनटाइम द्वारा। हालांकि, जब प्रोग्रामर ढेर पर मेमोरी उत्पन्न करते हैं और कचरा संग्रहकर्ता (सी और सी ++ के मामले में) की अनुपस्थिति में इसे हटाने में विफल होते हैं, तो स्मृति रिसाव विकसित होता है। साथ ही, अगर हम उस स्मृति को हटाए बिना स्मृति के एक हिस्से के सभी संदर्भ खो देते हैं, तो हमारे पास स्मृति रिसाव है। हमारा प्रोग्राम उस मेमोरी का स्वामी बना रहेगा, लेकिन उसके पास इसे फिर से उपयोग करने का कोई तरीका नहीं है। थोड़ी सी मेमोरी लीक कोई समस्या नहीं है, लेकिन अगर कोई प्रोग्राम बड़ी मात्रा में मेमोरी आवंटित करता है और इसे कभी नहीं हटाता है, तो प्रोग्राम की मेमोरी फ़ुटप्रिंट बढ़ती रहेगी, जिसके परिणामस्वरूप सेवा से इनकार किया जा सकता है। जब कोई प्रोग्राम बाहर निकलता है, तो ऑपरेटिंग सिस्टम उसके पास मौजूद सभी मेमोरी को तुरंत रिकवर कर लेता है। नतीजतन, एक स्मृति रिसाव केवल एक प्रोग्राम को प्रभावित करता है जब वह चल रहा हो; कार्यक्रम समाप्त होने के बाद इसका कोई प्रभाव नहीं पड़ता है। आइए मेमोरी लीक के प्रमुख परिणामों पर चलते हैं। मेमोरी लीक उपलब्ध मेमोरी (हीप मेमोरी) की मात्रा को कम करके कंप्यूटर के प्रदर्शन को कम करता है। यह अंततः पूरे या सिस्टम के एक हिस्से को सही ढंग से काम करना बंद कर देता है या गंभीर रूप से धीमा कर देता है। क्रैश आमतौर पर मेमोरी लीक से जुड़े होते हैं। मेमोरी लीक को रोकने के तरीके का पता लगाने के लिए हमारा दृष्टिकोण उस प्रोग्रामिंग भाषा के आधार पर अलग-अलग होगा जिसका हम उपयोग कर रहे हैं। मेमोरी लीक एक छोटी और लगभग "अनदेखी समस्या" के रूप में शुरू हो सकता है, लेकिन वे बहुत तेज़ी से बढ़ सकते हैं और सिस्टम को प्रभावित कर सकते हैं। जहां भी संभव हो, हमें उनकी तलाश में रहना चाहिए और उन्हें बढ़ने के बजाय उन्हें सुधारने के लिए कार्रवाई करनी चाहिए। मेमोरी असुरक्षित बनाम मेमोरी लीक मेमोरी लीक और मेमोरी असुरक्षित दो प्रकार के मुद्दे हैं जिन पर रोकथाम और उपचार के मामले में सबसे अधिक ध्यान दिया गया है। यह ध्यान रखना महत्वपूर्ण है कि एक को ठीक करने से दूसरे को स्वचालित रूप से ठीक नहीं किया जाता है। विभिन्न प्रकार की यादें और वे कैसे काम करती हैं इससे पहले कि हम आगे बढ़ें, विभिन्न प्रकार की मेमोरी को समझना महत्वपूर्ण है जो हमारा कोड रनटाइम पर उपयोग करेगा। स्मृति दो प्रकार की होती है, जो इस प्रकार हैं, और इन स्मृतियों की संरचना अलग-अलग होती है। प्रोसेसर रजिस्टर स्थिर ढेर ढेर और मेमोरी प्रकार दोनों इस पोस्ट के दायरे से बाहर हैं। प्रोसेसर रजिस्टर स्थिर स्टैक मेमोरी और यह कैसे काम करता है स्टैक डेटा को प्राप्त होने के क्रम में संग्रहीत करता है और इसे उल्टे क्रम में हटा देता है। आइटम को स्टैक से (LIFO) ऑर्डर में एक्सेस किया जा सकता है। स्टैक पर डेटा जोड़ने को "पुशिंग" कहा जाता है और स्टैक से डेटा को हटाने को "पॉपिंग" कहा जाता है। लास्ट इन, फर्स्ट आउट स्टैक पर संग्रहीत सभी डेटा का एक ज्ञात, निश्चित आकार होना चाहिए। संकलन समय पर अज्ञात आकार वाले डेटा या बाद में बदल सकने वाले आकार को इसके बजाय हीप पर संग्रहीत किया जाना चाहिए। डेवलपर्स के रूप में, हमें स्टैक मेमोरी और के बारे में चिंता करने की ज़रूरत नहीं है; स्टैक मेमोरी का आवंटन और डीलोकेशन कंपाइलर द्वारा "स्वचालित रूप से किया जाता है"। इसका तात्पर्य यह है कि जब स्टैक पर डेटा अब प्रासंगिक (दायरे से बाहर) नहीं है, तो यह हमारे हस्तक्षेप की आवश्यकता के बिना स्वचालित रूप से हटा दिया जाता है। आवंटन डीलोकेशन इस प्रकार की मेमोरी आवंटन को के रूप में भी जाना जाता है, क्योंकि जैसे ही फ़ंक्शन अपना निष्पादन समाप्त करता है, उस फ़ंक्शन से संबंधित सभी डेटा "स्वचालित रूप से" स्टैक से बाहर निकल जाता है। अस्थायी मेमोरी आवंटन जंग में सभी आदिम प्रकार ढेर पर रहते हैं। संख्याएं, वर्ण, स्लाइस, बूलियन, निश्चित आकार के सरणी, आदिम युक्त टुपल्स, और फ़ंक्शन पॉइंटर्स जैसे प्रकार सभी स्टैक पर बैठ सकते हैं। हीप मेमोरी और यह कैसे काम करता है स्टैक के विपरीत, जब हम ढेर पर डेटा डालते हैं, तो हम एक निश्चित मात्रा में स्थान का अनुरोध करते हैं। मेमोरी आवंटक ढेर में एक बड़ी पर्याप्त खाली जगह का पता लगाता है, इसे उपयोग के रूप में चिह्नित करता है, और उस स्थान के पते का संदर्भ देता है। इसे कहा जाता है। आवंटन ढेर पर आवंटन ढेर को धक्का देने से धीमा है क्योंकि आवंटक को नया डेटा डालने के लिए खाली स्थान की तलाश नहीं करनी पड़ती है। इसके अलावा, क्योंकि हमें ढेर पर डेटा प्राप्त करने के लिए एक पॉइंटर का पालन करना चाहिए, यह स्टैक पर डेटा तक पहुंचने से धीमा है। स्टैक के विपरीत, जिसे संकलन समय पर आवंटित और हटा दिया जाता है, हीप मेमोरी को प्रोग्राम के निर्देशों के निष्पादन के दौरान आवंटित और हटा दिया जाता है। कुछ प्रोग्रामिंग भाषाओं में, हीप मेमोरी आवंटित करने के लिए, हम कीवर्ड का उपयोग करते हैं। यह कीवर्ड (उर्फ ) ढेर पर स्मृति आवंटन के अनुरोध को दर्शाता है। यदि ढेर पर पर्याप्त स्मृति उपलब्ध है, तो ऑपरेटर स्मृति को प्रारंभ करता है और उस नई आवंटित स्मृति का अद्वितीय पता देता है। new new ऑपरेटर new यह ध्यान देने योग्य है कि हीप मेमोरी को प्रोग्रामर या रनटाइम द्वारा "स्पष्ट रूप से" हटा दिया जाता है। विभिन्न अन्य प्रोग्रामिंग भाषाएँ स्मृति सुरक्षा की गारंटी कैसे देती हैं? जब स्मृति प्रबंधन की बात आती है, विशेष रूप से मेमोरी को ढेर करने की, तो हम अपनी प्रोग्रामिंग भाषाओं को निम्नलिखित विशेषताओं के लिए पसंद करेंगे: हम जितनी जल्दी हो सके स्मृति को जारी करना पसंद करेंगे जब इसकी आवश्यकता नहीं होगी, बिना रनटाइम ओवरहेड के। हमें कभी भी किसी ऐसे डेटा का संदर्भ नहीं रखना चाहिए जिसे मुक्त कर दिया गया हो (उर्फ एक लटकता हुआ संदर्भ)। अन्यथा, क्रैश और सुरक्षा समस्याएँ हो सकती हैं। प्रोग्रामिंग भाषाओं द्वारा विभिन्न तरीकों से मेमोरी सुरक्षा सुनिश्चित की जाती है: (सी, सी ++ द्वारा अपनाया गया) स्पष्ट मेमोरी डीलोकेशन (जावा, पायथन और सी # द्वारा अपनाया गया) स्वचालित या अंतर्निहित मेमोरी डीलोकेशन क्षेत्र आधारित स्मृति प्रबंधन रैखिक या अद्वितीय प्रकार की प्रणालियाँ और दोनों इस पद के दायरे से बाहर हैं। क्षेत्र-आधारित स्मृति प्रबंधन रैखिक प्रकार प्रणाली मैनुअल या स्पष्ट मेमोरी डीललोकेशन प्रोग्रामर को स्पष्ट स्मृति प्रबंधन का उपयोग करते समय आवंटित स्मृति को "मैन्युअल रूप से" जारी या मिटा देना चाहिए। एक "डीलोकेशन" ऑपरेटर (उदाहरण के लिए, सी में ) स्पष्ट मेमोरी डीलोकेशन वाली भाषाओं में मौजूद है। delete सी और सी ++ जैसी सिस्टम भाषाओं में कचरा संग्रह बहुत महंगा है, इसलिए स्पष्ट स्मृति आवंटन मौजूद है। स्मृति को मुक्त करने की जिम्मेदारी प्रोग्रामर पर छोड़ने से प्रोग्रामर को चर के जीवन चक्र पर पूर्ण नियंत्रण देने का लाभ मिलता है। हालाँकि, यदि डीललोकेशन ऑपरेटरों का गलत तरीके से उपयोग किया जाता है, तो निष्पादन के दौरान एक सॉफ़्टवेयर त्रुटि हो सकती है। वास्तव में, यह मैनुअल आवंटन और जारी करने की प्रक्रिया त्रुटियों से ग्रस्त है। कुछ सामान्य कोडिंग त्रुटियों में शामिल हैं: लटकता हुआ संदर्भ स्मृति रिसाव इसके बावजूद, हमने कचरा संग्रहण पर मैनुअल मेमोरी प्रबंधन को प्राथमिकता दी क्योंकि यह हमें अधिक नियंत्रण देता है और बेहतर प्रदर्शन प्रदान करता है। ध्यान दें कि किसी भी सिस्टम प्रोग्रामिंग भाषा का लक्ष्य जितना संभव हो "धातु के करीब" प्राप्त करना है। दूसरे शब्दों में, वे ट्रेडऑफ़ में सुविधा सुविधाओं पर बेहतर प्रदर्शन का पक्ष लेते हैं। यह पूरी तरह से हमारी (डेवलपर्स) जिम्मेदारी है कि हम यह सुनिश्चित करें कि हमारे द्वारा मुक्त किए गए मूल्य का कोई संकेतक कभी भी उपयोग नहीं किया जाता है। हाल के दिनों में, इन त्रुटियों से बचने के लिए कई सिद्ध पैटर्न रहे हैं, लेकिन यह सब कठोर कोड अनुशासन बनाए रखने के लिए उबलता है, जिसके लिए लगातार सही मेमोरी प्रबंधन पद्धति को लागू करने की आवश्यकता होती है। प्रमुख टेकअवे हैं: स्मृति प्रबंधन पर अधिक नियंत्रण रखें। लटकते संदर्भों और मेमोरी लीक के परिणामस्वरूप कम सुरक्षा। लंबे विकास समय में परिणाम। स्वचालित या अंतर्निहित मेमोरी डीललोकेशन जावा सहित सभी आधुनिक प्रोग्रामिंग भाषाओं की स्वचालित स्मृति प्रबंधन एक अनिवार्य विशेषता बन गई है। स्वचालित मेमोरी डीलोकेशन के मामले में, स्वचालित मेमोरी मैनेजर के रूप में कार्य करता है। ये कचरा संग्रहकर्ता समय-समय पर मेमोरी के ढेर और रीसायकल के माध्यम से जाते हैं जिनका उपयोग नहीं किया जा रहा है। वे हमारी ओर से स्मृति के आवंटन और रिलीज का प्रबंधन करते हैं। इसलिए हमें स्मृति प्रबंधन कार्यों को करने के लिए कोड लिखने की आवश्यकता नहीं है। यह बहुत अच्छा है क्योंकि कचरा संग्रहकर्ता हमें स्मृति प्रबंधन की जिम्मेदारी से मुक्त करते हैं। एक और फायदा यह है कि यह विकास के समय को कम करता है। कचरा संग्रहकर्ता दूसरी ओर, कचरा संग्रह में कई कमियां हैं। कचरा संग्रहण के दौरान, कार्यक्रम को रुकना चाहिए और आगे बढ़ने से पहले यह निर्धारित करने में समय व्यतीत करना चाहिए कि उसे क्या साफ करना है। इसके अलावा, स्वचालित मेमोरी प्रबंधन में मेमोरी की आवश्यकता अधिक होती है। यह इस तथ्य के कारण है कि एक कचरा संग्रहकर्ता हमारे लिए मेमोरी डीलोकेशन करता है, जो मेमोरी और सीपीयू चक्र दोनों का उपभोग करता है। परिणामस्वरूप, स्वचालित स्मृति प्रबंधन अनुप्रयोग प्रदर्शन को ख़राब कर सकता है, विशेष रूप से सीमित संसाधनों वाले बड़े अनुप्रयोगों में। प्रमुख टेकअवे हैं: डेवलपर्स को मैन्युअल रूप से मेमोरी जारी करने की आवश्यकता को समाप्त करता है। बिना लटके संदर्भ या मेमोरी लीक के कुशल मेमोरी सुरक्षा प्रदान करता है। सरल और सीधा कोड। तेजी से विकास चक्र। स्मृति प्रबंधन पर कम नियंत्रण रखें। विलंबता का कारण बनता है क्योंकि यह मेमोरी और सीपीयू चक्र दोनों का उपभोग करता है। रस्ट मेमोरी सुरक्षा की गारंटी कैसे देता है? कुछ भाषाएं प्रदान करती हैं, जो उस मेमोरी की तलाश करती है जो प्रोग्राम के चलने के दौरान अब उपयोग में नहीं है; दूसरों को प्रोग्रामर को करने की आवश्यकता होती है। इन दोनों मॉडलों के फायदे और नुकसान हैं। कचरा संग्रह, हालांकि शायद सबसे व्यापक रूप से उपयोग किया जाता है, में कुछ कमियां हैं; यह संसाधनों और प्रदर्शन की कीमत पर डेवलपर्स के लिए जीवन को आसान बनाता है। कचरा संग्रहण स्मृति को स्पष्ट रूप से आवंटित करने और जारी ऐसा कहने के बाद, एक कुशल स्मृति प्रबंधन देता है, जबकि दूसरा झूलने वाले संदर्भों और मेमोरी लीक को समाप्त करके उच्च प्रदान करता है। जंग दोनों दुनिया के लाभों को जोड़ती है। नियंत्रण सुरक्षा रस्ट अन्य दो की तुलना में चीजों के लिए एक अलग दृष्टिकोण लेता है, एक के आधार पर नियमों के एक सेट के साथ जो संकलक स्मृति सुरक्षा सुनिश्चित करने के लिए सत्यापित करता है। यदि इनमें से किसी भी नियम का उल्लंघन किया जाता है तो कार्यक्रम संकलित नहीं होगा। वास्तव में, स्वामित्व रनटाइम कचरा संग्रह को स्मृति सुरक्षा के लिए संकलन-समय जांच के साथ बदल देता है। स्वामित्व मॉडल स्वामित्व के अभ्यस्त होने में कुछ समय लगता है क्योंकि यह मेरे जैसे कई प्रोग्रामर के लिए एक नई अवधारणा है। स्वामित्व इस बिंदु पर, हमें एक बुनियादी समझ है कि मेमोरी में डेटा कैसे संग्रहीत किया जाता है। आइए रस्ट में को अधिक बारीकी से देखें। जंग की सबसे बड़ी विशिष्ट विशेषता स्वामित्व है, जो संकलन-समय पर स्मृति सुरक्षा सुनिश्चित करती है। स्वामित्व शुरू करने के लिए, आइए "स्वामित्व" को इसके सबसे शाब्दिक अर्थ में परिभाषित करें। स्वामित्व "कुछ" के "मालिक" और "नियंत्रित" कानूनी कब्जे की स्थिति है। इसके साथ ही, हमें यह पहचानना होगा और । जंग में, प्रत्येक मान का एक चर होता है जिसे उसका कहा जाता है। सीधे शब्दों में कहें तो, एक वैरिएबल एक मालिक होता है, और एक वैरिएबल का मान वह होता है जो मालिक का मालिक होता है और उसे नियंत्रित करता है। कि मालिक कौन है और मालिक क्या मालिक है क्या नियंत्रित करता है स्वामी एक स्वामित्व मॉडल के साथ, स्मृति स्वचालित रूप से जारी (मुक्त) हो जाती है, जब इसका स्वामित्व वाला चर दायरे से बाहर हो जाता है। जब मूल्य दायरे से बाहर हो जाते हैं या किसी अन्य कारण से उनका जीवनकाल समाप्त हो जाता है, तो उनके विनाशक कहलाते हैं। एक विनाशक, विशेष रूप से एक स्वचालित विनाशक, एक ऐसा कार्य है जो संदर्भों को हटाकर प्रोग्राम से एक मूल्य के निशान को हटा देता है और स्मृति को मुक्त करता है। उधार चेकर जंग के माध्यम से स्वामित्व को लागू करता है, a . बॉरो चेकर रस्ट कंपाइलर में एक घटक है जो इस बात पर नज़र रखता है कि पूरे कार्यक्रम में डेटा का उपयोग कहाँ किया जाता है, और स्वामित्व नियमों का पालन करके, यह निर्धारित करने में सक्षम है कि डेटा को कहाँ जारी करने की आवश्यकता है। इसके अलावा, बॉरो चेकर यह सुनिश्चित करता है कि डिलीकेटेड मेमोरी को रनटाइम पर कभी भी एक्सेस नहीं किया जा सकता है। यह समवर्ती उत्परिवर्तन (संशोधन) के कारण होने वाली डेटा दौड़ की संभावना को भी समाप्त करता है। उधार चेकर स्थिर विश्लेषक स्वामित्व नियम जैसा कि पहले कहा गया है, स्वामित्व मॉडल नियमों के एक सेट पर बनाया गया है जिसे नियम कहा जाता है, और ये नियम अपेक्षाकृत सरल हैं। रस्ट कंपाइलर (rustc) इन नियमों को लागू करता है: स्वामित्व रस्ट में, प्रत्येक मान का एक चर होता है जिसे उसका स्वामी कहा जाता है। एक समय में केवल एक ही स्वामी हो सकता है। जब मालिक दायरे से बाहर हो जाता है, तो मान छोड़ दिया जाएगा। निम्नलिखित स्मृति त्रुटियाँ इन संकलन-समय जाँच स्वामित्व नियमों द्वारा सुरक्षित हैं: यह वह जगह है जहां एक संदर्भ एक स्मृति पते को इंगित करता है जिसमें अब वह डेटा नहीं होता है जिसे सूचक संदर्भित कर रहा था; यह सूचक शून्य या यादृच्छिक डेटा को इंगित करता है। डैंगलिंग संदर्भ: एक्सेस किया जाता है, जो क्रैश हो सकता है। इस मेमोरी लोकेशन का उपयोग हैकर्स कोड निष्पादित करने के लिए भी कर सकते हैं। फ्री के बाद उपयोग करें: यह वह जगह है जहां मेमोरी को एक बार मुक्त करने के बाद यह वह जगह है जहाँ आवंटित मेमोरी को मुक्त किया जाता है, और फिर से मुक्त किया जाता है। इससे प्रोग्राम क्रैश हो सकता है, संभावित रूप से संवेदनशील जानकारी उजागर हो सकती है। यह एक हैकर को उनके द्वारा चुने गए किसी भी कोड को चलाने की अनुमति देता है। डबल फ़्रीज़: यह वह जगह है जहां प्रोग्राम मेमोरी तक पहुंचने का प्रयास करता है, इसे एक्सेस करने की अनुमति नहीं है। सेगमेंटेशन दोष: यह वह जगह है जहां डेटा की मात्रा मेमोरी बफर की स्टोरेज क्षमता से अधिक हो जाती है, जिससे प्रोग्राम क्रैश हो जाता है। बफर ओवररन: प्रत्येक स्वामित्व नियम के विवरण में जाने से पहले, , , और के बीच के अंतर को समझना महत्वपूर्ण है। copy move clone प्रतिलिपि एक निश्चित आकार (विशेष रूप से आदिम प्रकार) के साथ एक प्रकार को पर संग्रहीत किया जा सकता है और इसका दायरा समाप्त होने पर पॉप ऑफ किया जा सकता है, और एक नया, स्वतंत्र चर बनाने के लिए जल्दी और आसानी से कॉपी किया जा सकता है यदि कोड के दूसरे भाग में समान मान की आवश्यकता होती है एक अलग दायरा। चूंकि स्टैक मेमोरी की प्रतिलिपि बनाना सस्ता और तेज़ है, निश्चित आकार वाले आदिम प्रकारों को सेमेन्टिक्स कहा जाता है। यह सस्ते में एक संपूर्ण प्रतिकृति (एक डुप्लिकेट) बनाता है। स्टैक कॉपी यह ध्यान देने योग्य है कि निश्चित आकार वाले आदिम प्रकार प्रतिलिपि बनाने के लिए प्रतिलिपि विशेषता को लागू करते हैं। let x = "hello"; let y = x; println!("{}", x) // hello println!("{}", y) // hello (आवंटित ढेर, और बढ़ने योग्य) और (निश्चित आकार, और उत्परिवर्तित नहीं किया जा सकता)। जंग में, दो प्रकार के तार होते हैं: String &str क्योंकि को स्टैक पर संग्रहीत किया जाता है, के लिए दूसरी प्रतिलिपि बनाने के लिए इसके मान की प्रतिलिपि बनाना आसान होता है। ढेर पर संग्रहीत मान के लिए यह मामला नहीं है। स्टैक फ्रेम इस तरह दिखता है: x y डुप्लिकेट डेटा प्रोग्राम रनटाइम और मेमोरी खपत को बढ़ाता है। इसलिए, कॉपी करना डेटा के बड़े हिस्से के लिए उपयुक्त नहीं है। कदम रस्ट शब्दावली में, "चाल" का अर्थ है कि स्मृति का स्वामित्व किसी अन्य स्वामी को स्थानांतरित कर दिया गया है। ढेर पर संग्रहीत जटिल प्रकारों के मामले पर विचार करें। let s1 = String::from("hello"); let s2 = s1; हम मान सकते हैं कि दूसरी पंक्ति (यानी ) में मान की एक प्रति बनाएगी और इसे से बांध देगी। पर ये स्थिति नहीं है। let s2 = s1; s1 s2 हुड के नीचे के साथ क्या हो रहा है यह देखने के लिए नीचे दिए गए एक पर एक नज़र डालें। एक स्ट्रिंग तीन भागों से बनी होती है, जो पर संग्रहीत होती है। वास्तविक सामग्री (हैलो, इस मामले में) पर संग्रहीत हैं। String स्टैक ढेर - उस मेमोरी को इंगित करता है जिसमें स्ट्रिंग की सामग्री होती है। पॉइंटर - यह कितनी मेमोरी है, बाइट्स में, की सामग्री वर्तमान में उपयोग कर रही है। लंबाई String - यह मेमोरी की कुल मात्रा है, बाइट्स में, जो को आवंटक से प्राप्त हुई है। क्षमता String दूसरे शब्दों में कहें तो मेटाडेटा को स्टैक पर रखा जाता है जबकि वास्तविक डेटा को हीप पर रखा जाता है। जब हम से असाइन करते हैं, तो मेटाडेटा की प्रतिलिपि बनाई जाती है, जिसका अर्थ है कि हम पॉइंटर, लंबाई और स्टैक पर मौजूद क्षमता की प्रतिलिपि बनाते हैं। हम उस डेटा को ढेर पर कॉपी नहीं करते हैं जिसे पॉइंटर संदर्भित करता है। मेमोरी में डेटा का प्रतिनिधित्व नीचे जैसा दिखता है: s1 s2 String यह ध्यान देने योग्य है कि प्रतिनिधित्व नीचे की तरह दिखता है, जो कि अगर रस्ट ने हीप डेटा की नकल की तो मेमोरी कैसी दिखेगी। यदि जंग ने ऐसा किया है, तो ऑपरेशन रनटाइम प्रदर्शन के मामले में बेहद धीमा हो सकता है यदि हीप डेटा बड़ा था। नहीं s2 = s1 ध्यान दें कि जब जटिल प्रकार अब दायरे में नहीं होते हैं, तो रस्ट फ़ंक्शन को हीप मेमोरी को स्पष्ट रूप से हटाने के लिए कॉल करेगा। हालाँकि, चित्र 6 में दोनों डेटा पॉइंटर्स एक ही स्थान की ओर इशारा कर रहे हैं, जो कि रस्ट के काम करने का तरीका नहीं है। हम जल्द ही विवरण में शामिल होंगे। drop जैसा कि पहले कहा गया है, जब हम से असाइन करते हैं, तो चर को के मेटाडेटा (सूचक, लंबाई और क्षमता) की एक प्रति प्राप्त होती है। लेकिन को को सौंपे जाने के बाद क्या होता है? रस्ट अब को मान्य नहीं मानता। हां, तुमने उसे ठीक पढ़ा। s1 s2 s2 s1 s1 s2 s1 आइए इस बारे में एक पल के लिए असाइनमेंट पर विचार करें। विचार करें कि क्या होता है यदि रस्ट इस असाइनमेंट के बाद भी को मान्य मानता है। जब और दायरे से बाहर हो जाते हैं, तो वे दोनों एक ही मेमोरी को मुक्त करने का प्रयास करेंगे। उह-ओह, यह अच्छा नहीं है। इसे कहा जाता है, और यह मेमोरी सेफ्टी बग्स में से एक है। स्मृति भ्रष्टाचार का परिणाम स्मृति को दो बार मुक्त करने से हो सकता है, जिससे सुरक्षा जोखिम उत्पन्न हो सकता है। let s2 = s1 s1 s2 s1 डबल फ्री एरर स्मृति सुरक्षा सुनिश्चित करने के लिए, रस्ट को लाइन के बाद अमान्य माना जाता है । इसलिए, जब अब दायरे में नहीं है, रस्ट को कुछ भी जारी करने की आवश्यकता नहीं है। जाँच करें कि क्या होता है यदि हम के निर्माण के बाद का उपयोग करने का प्रयास करते हैं। s1 let s2 = s1 s1 s2 s1 let s1 = String::from("hello"); let s2 = s1; println!("{}, world!", s1); // Won't compile. We'll get an error. हमें नीचे की तरह एक त्रुटि मिलेगी क्योंकि जंग आपको अमान्य संदर्भ का उपयोग करने से रोकता है: $ cargo run Compiling playground v0.0.1 (/playground) error[E0382]: borrow of moved value: `s1` --> src/main.rs:6:28 | 3 | let s1 = String::from("hello"); | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait 4 | let s2 = s1; | -- value moved here 5 | 6 | println!("{}, world!", s1); | ^^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0382`. चूंकि रस्ट ने की मेमोरी के स्वामित्व को पर ले को "स्थानांतरित" कर दिया, इसलिए इसे अमान्य माना गया। यहाँ s1 के अमान्य होने के बाद स्मृति प्रतिनिधित्व है: s1 s2 let s2 = s1 s1 जब केवल वैध रहता है, तो यह अकेले ही मेमोरी को मुक्त कर देगा जब यह दायरे से बाहर हो जाएगा। नतीजतन, जंग में की संभावना समाप्त हो जाती है। यह तो बहुत ही अच्छी बात है! s2 दोहरी मुक्त त्रुटि क्लोन यदि हम केवल स्टैक डेटा ही नहीं, बल्कि के हीप डेटा को गहराई से कॉपी चाहते हैं, तो हम नामक एक विधि का उपयोग कर सकते हैं। क्लोन विधि का उपयोग करने का एक उदाहरण यहां दिया गया है: String करना clone let s1 = String::from("hello"); let s2 = s1.clone(); println!("s1 = {}, s2 = {}", s1, s2); क्लोन विधि का उपयोग करते समय, ढेर डेटा s2 में कॉपी हो जाता है। यह पूरी तरह से काम करता है और निम्नलिखित व्यवहार उत्पन्न करता है: क्लोन पद्धति के उपयोग के गंभीर परिणाम होते हैं; यह न केवल डेटा को कॉपी करता है, बल्कि यह दोनों के बीच किसी भी बदलाव को सिंक्रोनाइज़ भी नहीं करता है। सामान्य तौर पर, क्लोनों को सावधानीपूर्वक और परिणामों के बारे में पूरी जागरूकता के साथ नियोजित किया जाना चाहिए। अब तक, हमें कॉपी, मूव और क्लोन के बीच अंतर करने में सक्षम होना चाहिए। आइए अब प्रत्येक स्वामित्व नियम को अधिक विस्तार से देखें। स्वामित्व नियम 1 प्रत्येक मान का एक चर होता है जिसे उसका स्वामी कहा जाता है। इसका तात्पर्य है कि सभी मान चर के स्वामित्व में हैं। नीचे दिए गए उदाहरण में, वेरिएबल हमारे स्ट्रिंग के पॉइंटर का मालिक है, और दूसरी लाइन में, वेरिएबल का मान 1 है। s x let s = String::from("Rule 1"); let n = 1; स्वामित्व नियम 2 एक निश्चित समय में किसी मूल्य का केवल एक स्वामी हो सकता है। किसी के पास कई पालतू जानवर हो सकते हैं, लेकिन जब स्वामित्व मॉडल की बात आती है, तो किसी भी समय केवल एक ही मूल्य होता है :-) आइए का उपयोग करके उदाहरण देखें, जो निश्चित आकार के संकलन समय पर ज्ञात हैं। प्राइमेटिव let x = 10; let y = x; let z = x; हमने 10 लिया है और इसे को सौंपा है; दूसरे शब्दों में, के पास 10 है। फिर हम ले रहे हैं और इसे को असाइन कर रहे हैं और हम इसे को भी असाइन कर रहे हैं। हम जानते हैं कि एक निश्चित समय में केवल एक ही स्वामी हो सकता है, लेकिन हमें यहां कोई त्रुटि नहीं मिल रही है। तो यहाँ क्या हो रहा है कि संकलक हर बार की प्रतियां बना रहा है जब हम इसे एक नए चर के लिए असाइन करते हैं। x x x y z x इसके लिए स्टैक फ्रेम इस प्रकार होगा: , और । हालांकि, ऐसा प्रतीत नहीं होता है: , , और । जैसा कि हम जानते हैं, इस मान 10 का एकमात्र स्वामी है, और न तो और न ही इस मान का स्वामी हो सकता है। x = 10 y = 10 z = 10 x = 10 y = x z = x x y z क्योंकि स्टैक मेमोरी की प्रतिलिपि बनाना सस्ता और तेज़ है, एक निश्चित आकार वाले आदिम प्रकारों को शब्दार्थ कहा जाता है, जबकि जटिल प्रकार स्वामित्व को करते हैं, जैसा कि पहले कहा गया था। इस प्रकार, इस मामले में, संकलक बनाता है। कॉपी स्थानांतरित प्रतियां इस बिंदु पर, का व्यवहार अन्य प्रोग्रामिंग भाषाओं के समान है। स्वामित्व के नियमों को स्पष्ट करने के लिए, हमें एक जटिल डेटा प्रकार की आवश्यकता है। परिवर्तनीय बंधन आइए ढेर पर संग्रहीत डेटा को देखें और देखें कि रस्ट कैसे समझता है कि इसे कब साफ करना है; इस उपयोग के मामले के लिए स्ट्रिंग प्रकार एक उत्कृष्ट उदाहरण है। हम स्ट्रिंग के स्वामित्व-संबंधी व्यवहार पर ध्यान देंगे; हालाँकि, ये सिद्धांत अन्य जटिल डेटा प्रकारों पर भी लागू होते हैं। जटिल प्रकार, जैसा कि हम जानते हैं, ढेर पर डेटा का प्रबंधन करता है, और इसकी सामग्री संकलन समय पर अज्ञात होती है। आइए उसी उदाहरण को देखें जो हमने पहले देखा है: let s1 = String::from("hello"); let s2 = s1; println!("{}, world!", s1); // Won't compile. We'll get an error. प्रकार के मामले में, आकार का विस्तार हो सकता है और ढेर पर संग्रहीत किया जा सकता है। इसका मतलब है की: String रनटाइम पर, मेमोरी एलोकेटर से मेमोरी का अनुरोध किया जाना चाहिए (चलिए इसे पहला भाग कहते हैं)। जब हम अपने का उपयोग कर रहे होते हैं, तो हमें इस मेमोरी को वापस आवंटक को वापस (रिलीज़) करने की आवश्यकता होती है (चलिए इसे दूसरा भाग कहते हैं)। String हमने (डेवलपर्स) पहले भाग का ध्यान रखा: जब हम कॉल करते हैं, तो इसका कार्यान्वयन उस मेमोरी का अनुरोध करता है जिसकी उसे आवश्यकता होती है। प्रोग्रामिंग भाषाओं में यह हिस्सा लगभग सामान्य है। String::from हालांकि, दूसरा भाग अलग है। कचरा संग्रहकर्ता (जीसी) वाली भाषाओं में, जीसी उस मेमोरी को ट्रैक और साफ़ करता है जो अब उपयोग में नहीं है, और हमें इसके बारे में चिंता करने की ज़रूरत नहीं है। कचरा संग्रहकर्ता के बिना भाषाओं में, यह हमारी जिम्मेदारी है कि हम यह पहचानें कि स्मृति की अब आवश्यकता नहीं है और इसे स्पष्ट रूप से जारी करने के लिए कहें। इसे सही ढंग से करना हमेशा एक चुनौतीपूर्ण प्रोग्रामिंग कार्य रहा है: अगर हम भूल गए तो हम याददाश्त बर्बाद कर देंगे। यदि हम इसे बहुत जल्दी करते हैं तो हमारे पास एक अमान्य चर होगा। अगर हम इसे दो बार करते हैं तो हमें एक बग मिलेगा। रस्ट हमारे जीवन को आसान बनाने के लिए मेमोरी डीलोकेशन को एक नए तरीके से हैंडल करता है: एक बार जब वेरिएबल का मालिक होता है तो मेमोरी अपने आप वापस आ जाती है। चलो व्यापार पर वापस। जंग में, जटिल प्रकारों के लिए, एक चर के लिए एक मान निर्दिष्ट करने, इसे किसी फ़ंक्शन में पास करने, या किसी फ़ंक्शन से इसे वापस करने जैसे संचालन मान की प्रतिलिपि नहीं बनाते हैं: वे इसे स्थानांतरित करते हैं। इसे सीधे शब्दों में कहें, तो जटिल प्रकार स्वामित्व को स्थानांतरित करते हैं। जब जटिल प्रकार अब दायरे में नहीं होते हैं, तो रस्ट ड्रॉप फ़ंक्शन को स्पष्ट रूप से हीप मेमोरी को हटाने के लिए कॉल करेगा। स्वामित्व नियम 3 जब मालिक दायरे से बाहर हो जाता है, तो मान छोड़ दिया जाएगा। पिछले मामले पर फिर से विचार करें: let s1 = String::from("hello"); let s2 = s1; println!("{}, world!", s1); // Won't compile. The value of s1 has already been dropped. को को सौंपे जाने के बाद का मान गिर गया है ( असाइनमेंट स्टेटमेंट में)। इस प्रकार, इस असाइनमेंट के बाद अब मान्य नहीं है। यहाँ s1 को छोड़ने के बाद मेमोरी का प्रतिनिधित्व है: s1 s2 s1 let s2 = s1 s1 स्वामित्व कैसे चलता है जंग कार्यक्रम में स्वामित्व को एक चर से दूसरे चर में स्थानांतरित करने के तीन तरीके हैं: एक चर के मान को दूसरे चर में निर्दिष्ट करना (इस पर पहले ही चर्चा की जा चुकी है)। किसी फ़ंक्शन के लिए मान पास करना। समारोह से लौट रहे हैं। किसी फ़ंक्शन के लिए मान पास करना किसी फ़ंक्शन के लिए एक मान पास करना शब्दार्थ है जो एक चर के लिए एक मान निर्दिष्ट करने के समान है। असाइनमेंट की तरह ही, किसी फंक्शन में वेरिएबल को पास करने से वह मूव या कॉपी हो जाता है। इस उदाहरण पर एक नज़र डालें, जो कॉपी और मूव दोनों मामलों को दिखाता है: fn main() { let s = String::from("hello"); // s comes into scope move_ownership(s); // s's value moves into the function... // so it's no longer valid from this // point forward let x = 5; // x comes into scope makes_copy(x); // x would move into the function // It follows copy semantics since it's // primitive, so we use x afterward } // Here, x goes out of scope, then s. But because s's value was moved, nothing // special happens. fn move_ownership(some_string: String) { // some_string comes into scope println!("{}", some_string); } // Here, some_string goes out of scope and `drop` is called. // The occupied memory is freed. fn makes_copy(some_integer: i32) { // some_integer comes into scope println!("{}", some_integer); } // Here, some_integer goes out of scope. Nothing special happens. यदि हमने पर कॉल के बाद s का उपयोग करने का प्रयास किया, तो जंग एक संकलन-समय त्रुटि फेंक देगा। move_ownership एक समारोह से लौटना लौटाने वाले मान भी स्वामित्व स्थानांतरित कर सकते हैं। नीचे दिया गया उदाहरण एक फ़ंक्शन दिखाता है जो पिछले उदाहरण के समान एनोटेशन के साथ एक मान लौटाता है। fn main() { let s1 = gives_ownership(); // gives_ownership moves its return // value into s1 let s2 = String::from("hello"); // s2 comes into scope let s3 = takes_and_gives_back(s2); // s2 is moved into // takes_and_gives_back, which also // moves its return value into s3 } // Here, s3 goes out of scope and is dropped. s2 was moved, so nothing // happens. s1 goes out of scope and is dropped. fn gives_ownership() -> String { // gives_ownership will move its // return value into the function // that calls it let some_string = String::from("yours"); // some_string comes into scope some_string // some_string is returned and // moves out to the calling // function } // This function takes a String and returns it fn takes_and_gives_back(a_string: String) -> String { // a_string comes into // scope a_string // a_string is returned and moves out to the calling function } एक चर का स्वामित्व हमेशा एक ही पैटर्न का अनुसरण करता है: । जब तक डेटा का स्वामित्व किसी अन्य चर में स्थानांतरित नहीं किया जाता है, जब एक चर जिसमें ढेर पर डेटा शामिल होता है, गुंजाइश से बाहर हो जाता है, तो मान द्वारा साफ हो जाएगा। एक मान को तब स्थानांतरित किया जाता है जब इसे किसी अन्य चर को सौंपा जाता है drop उम्मीद है, यह हमें एक बुनियादी समझ देता है कि एक मॉडल क्या है और यह कैसे प्रभावित करता है कि रस्ट मूल्यों को कैसे संभालता है, जैसे कि उन्हें एक दूसरे को सौंपना और उन्हें कार्यों में और बाहर करना। स्वामित्व पकड़ना। एक बात और… जंग के स्वामित्व मॉडल, जैसा कि सभी अच्छी चीजों के साथ होता है, में कुछ कमियां होती हैं। एक बार जब हम रस्ट पर काम करना शुरू करते हैं तो हमें कुछ असुविधाओं का तुरंत एहसास होता है। हमने देखा होगा कि स्वामित्व लेना और फिर प्रत्येक फ़ंक्शन के साथ स्वामित्व वापस करना थोड़ा असुविधाजनक होता है। यह कष्टप्रद है कि यदि हम किसी फ़ंक्शन द्वारा लौटाए गए किसी अन्य डेटा के अलावा, किसी फ़ंक्शन में हम जो कुछ भी पास करते हैं, उसे फिर से उपयोग करना चाहते हैं, तो उसे वापस करना होगा। क्या होगा यदि हम चाहते हैं कि कोई फ़ंक्शन किसी मान का स्वामित्व लिए बिना उसका उपयोग करे? निम्नलिखित उदाहरण पर विचार करें। नीचे दिए गए कोड के परिणामस्वरूप एक त्रुटि होगी क्योंकि , अब फ़ंक्शन द्वारा उपयोग नहीं किया जा सकता है ( ) print_vector v main println! fn main() { let v = vec![10,20,30]; print_vector(v); println!("{}", v[0]); // this line gives us an error } fn print_vector(x: Vec<i32>) { println!("Inside print_vector function {:?}",x); } स्वामित्व को ट्रैक करना काफी आसान लग सकता है, लेकिन जब हम बड़े और जटिल कार्यक्रमों से निपटना शुरू करते हैं तो यह जटिल हो सकता है। इसलिए हमें स्वामित्व को स्थानांतरित किए बिना मूल्यों को स्थानांतरित करने का एक तरीका चाहिए, जहां की अवधारणा चलन में आती है। उधार लेने उधार उधार लेना, अपने शाब्दिक अर्थ में, इसे वापस करने के वादे के साथ कुछ प्राप्त करने का संदर्भ देता है। जंग के संदर्भ में, इसके स्वामित्व का दावा किए बिना मूल्य तक पहुंचने का एक तरीका है, क्योंकि इसे किसी बिंदु पर अपने मालिक को वापस करना होगा। उधार लेना जब हम कोई मूल्य उधार लेते हैं, तो हम उसके मेमोरी पते को ऑपरेटर के साथ संदर्भित करते हैं। A को कहा जाता है। संदर्भ स्वयं कुछ खास नहीं हैं - हुड के तहत, वे सिर्फ पते हैं। सी पॉइंटर्स से परिचित लोगों के लिए, एक संदर्भ स्मृति के लिए एक होता है जिसमें एक मान होता है जो किसी अन्य चर से संबंधित (उर्फ वाला) होता है। यह ध्यान देने योग्य है कि जंग में एक संदर्भ शून्य नहीं हो सकता है। वास्तव में, एक ; यह सूचक का सबसे बुनियादी प्रकार है। अधिकांश भाषाओं में केवल एक प्रकार का सूचक होता है, लेकिन रस्ट में केवल एक के बजाय विभिन्न प्रकार के सूचक होते हैं। संकेत और उनके विभिन्न प्रकार एक अलग विषय हैं जिस पर अलग से चर्चा की जाएगी। & & संदर्भ सूचक स्वामित्व संदर्भ एक सूचक है इसे सीधे शब्दों में कहें, तो रस्ट कुछ मूल्य के संदर्भ में मूल्य उधार लेने के लिए संदर्भित करता है, जिसे अंततः अपने मालिक को वापस करना होगा। आइए नीचे एक सरल उदाहरण देखें: let x = 5; let y = &x; println!("Value y={}", y); println!("Address of y={:p}", y); println!("Deref of y={}", *y); उपरोक्त निम्नलिखित आउटपुट उत्पन्न करता है: Value y=5 Address of y=0x7fff6c0f131c Deref of y=5 यहां, चर के संख्या है, जबकि अभी भी मान का स्वामी है। हम को का संदर्भ कहते हैं। जब दायरे से बाहर हो जाता है तो उधार समाप्त हो जाता है, और क्योंकि के पास मूल्य नहीं है, यह नष्ट नहीं होता है। एक मूल्य उधार लेने के लिए, ऑपरेटर द्वारा एक संदर्भ लें। p स्वरूपण, हेक्साडेसिमल के रूप में प्रस्तुत स्मृति स्थान के रूप में आउटपुट। y x स्वामित्व वाली उधार लेता x y x y y & {:p} उपरोक्त कोड में, "*" (अर्थात, एक तारांकन चिह्न) एक डीरेफरेंस ऑपरेटर है जो एक संदर्भ चर पर संचालित होता है। यह डीरेफ्रेंसिंग ऑपरेटर हमें पॉइंटर के मेमोरी एड्रेस में संग्रहीत मूल्य प्राप्त करने की अनुमति देता है। आइए देखें कि कैसे एक फ़ंक्शन उधार के माध्यम से स्वामित्व लिए बिना किसी मूल्य का उपयोग कर सकता है: fn main() { let v = vec![10,20,30]; print_vector(&v); println!("{}", v[0]); // can access v here as references can't move the value } fn print_vector(x: &Vec<i32>) { println!("Inside print_vector function {:?}", x); } हम स्वामित्व (यानी, ) को स्थानांतरित करने के बजाय फ़ंक्शन के लिए एक संदर्भ ( ) (उर्फ ) पास कर रहे हैं। नतीजतन, मुख्य फ़ंक्शन में फ़ंक्शन को कॉल करने के बाद, हम तक पहुंच सकते हैं। पास-बाय-वैल्यू print_vector &v पास-बाय-रेफरेंस print_vector v डेरेफरेंस ऑपरेटर के साथ मूल्य के सूचक के बाद जैसा कि पहले कहा गया है, एक संदर्भ एक प्रकार का सूचक है, और एक सूचक को कहीं और संग्रहीत मूल्य की ओर इशारा करते हुए एक तीर के रूप में माना जा सकता है। नीचे दिए गए उदाहरण पर विचार करें: let x = 5; let y = &x; assert_eq!(5, x); assert_eq!(5, *y); उपरोक्त कोड में, हम प्रकार के मान के लिए एक संदर्भ बनाते हैं और फिर डेटा के संदर्भ का पालन करने के लिए dereference ऑपरेटर का उपयोग करते हैं। चर में प्रकार का मान होता है, । हम को के संदर्भ के बराबर सेट करते हैं। i32 x i32 5 y x स्टैक मेमोरी इस प्रकार दिखाई देती है: हम दावा कर सकते हैं कि के बराबर है। हालाँकि, यदि हम में मान पर एक अभिकथन करना चाहते हैं, तो हमें उस मान के संदर्भ का पालन करना चाहिए जिसका वह उपयोग कर रहा है (इसलिए यहाँ dereference)। एक बार जब हम को हटा देते हैं, तो हमारे पास उस पूर्णांक मान तक पहुंच होती है, जिसे इंगित कर रहा है, जिसकी तुलना हम से कर सकते हैं। x 5 y *y y y 5 अगर हमने लिखने की कोशिश की इसके बजाय, हमें यह संकलन त्रुटि मिलेगी: assert_eq!(5, y); error[E0277]: can't compare `{integer}` with `&{integer}` --> src/main.rs:11:5 | 11 | assert_eq!(5, y); | ^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}` चूंकि वे अलग-अलग प्रकार के होते हैं, इसलिए किसी संख्या और किसी संख्या के संदर्भ की तुलना करने की अनुमति नहीं है। इसलिए, हमें उस मान के संदर्भ का पालन करने के लिए dereference ऑपरेटर का उपयोग करना चाहिए जो वह इंगित कर रहा है। संदर्भ डिफ़ॉल्ट रूप से अपरिवर्तनीय हैं चर की तरह, एक संदर्भ डिफ़ॉल्ट रूप से अपरिवर्तनीय है - इसे के साथ परिवर्तनशील बनाया जा सकता है, लेकिन केवल तभी जब उसका स्वामी भी परिवर्तनशील हो: mut let mut x = 5; let y = &mut x; अपरिवर्तनीय संदर्भों को साझा संदर्भ के रूप में भी जाना जाता है, जबकि परिवर्तनीय संदर्भों को अनन्य संदर्भों के रूप में भी जाना जाता है। नीचे दिए गए मामले पर विचार करें। हम संदर्भों को केवल पढ़ने के लिए पहुंच प्रदान कर रहे हैं क्योंकि हम के बजाय ऑपरेटर का उपयोग कर रहे हैं। भले ही स्रोत परिवर्तनशील हो, , और नहीं हैं, क्योंकि वे केवल-पढ़ने के लिए n उधार हैं। &mut & n ref_to_n another_ref_to_n let mut n = 10; let ref_to_n = &n; let another_ref_to_n = &n; उधार चेकर नीचे त्रुटि देगा: error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> src/main.rs:4:9 | 3 | let x = 5; | - help: consider changing this to be mutable: `mut x` 4 | let y = &mut x; | ^^^^^^ cannot borrow as mutable उधार नियम कोई सवाल कर सकता है कि एक पर हमेशा को प्राथमिकता क्यों नहीं दी जाएगी। अगर ऐसा है, तो रस्ट में सिमेंटिक क्यों होता है, और यह डिफ़ॉल्ट रूप से क्यों नहीं लेता है? कारण यह है कि जंग में एक मूल्य उधार लेना हमेशा संभव नहीं होता है। कुछ मामलों में ही उधार लेने की अनुमति है। कदम उधार लेने मूव उधार उधार लेने के नियमों का अपना सेट होता है, जिसे संकलन समय के दौरान सख्ती से लागू करता है। ये नियम को रोकने के लिए बनाए गए थे। वे इस प्रकार हैं: उधार लेने वाला चेकर डेटा दौड़ उधारकर्ता का दायरा मूल मालिक के दायरे से अधिक नहीं रह सकता। कई अपरिवर्तनीय संदर्भ हो सकते हैं, लेकिन केवल एक परिवर्तनशील संदर्भ हो सकता है। मालिकों के पास अपरिवर्तनीय या परिवर्तनशील संदर्भ हो सकते हैं, लेकिन एक ही समय में दोनों नहीं। सभी संदर्भ मान्य होने चाहिए (शून्य नहीं हो सकते)। संदर्भ स्वामी से अधिक नहीं रहना चाहिए संदर्भ का दायरा मूल्य के स्वामी के दायरे में होना चाहिए। अन्यथा, संदर्भ एक मुक्त मूल्य का उल्लेख कर सकता है, जिसके परिणामस्वरूप त्रुटि हो सकती है। उपयोग-बाद-मुक्त let x; { let y = 0; x = &y; } println!("{}", x); मालिक के दायरे से बाहर हो जाने के बाद उपरोक्त प्रोग्राम को डीरेफरेंस करने का प्रयास करता है। जंग इस त्रुटि को रोकता है। y x उपयोग के बाद मुक्त कई अपरिवर्तनीय संदर्भ, लेकिन केवल एक परिवर्तनीय संदर्भ की अनुमति है हमारे पास एक समय में डेटा के एक विशेष टुकड़े के लिए कई अपरिवर्तनीय संदर्भ (उर्फ साझा संदर्भ) हो सकते हैं, लेकिन एक पल में केवल एक परिवर्तनीय संदर्भ (उर्फ अनन्य संदर्भ) की अनुमति है। यह नियम को खत्म करने के लिए मौजूद है। जब दो संदर्भ एक ही समय में एक ही स्मृति स्थान की ओर इशारा करते हैं, उनमें से कम से कम एक लिख रहा है, और उनके कार्यों को सिंक्रनाइज़ किया जाता है, इसे डेटा दौड़ के रूप में जाना जाता है। डेटा दौड़ नहीं हमारे पास जितने चाहें उतने अपरिवर्तनीय संदर्भ हो सकते हैं क्योंकि वे डेटा को नहीं बदलते हैं। दूसरी ओर, उधार लेना हमें संकलन समय पर डेटा दौड़ की संभावना को रोकने के लिए एक समय में केवल एक परिवर्तनीय संदर्भ ( ) रखने के लिए प्रतिबंधित करता है। &mut आइए इसे देखें: fn main() { let mut s = String::from("hello"); let r1 = &mut s; let r2 = &mut s; println!("{}, {}", r1, r2); } उपरोक्त कोड जो दो परस्पर संदर्भ ( और ) से बनाने का प्रयास विफल हो जाएगा: r1 r2 s error[E0499]: cannot borrow `s` as mutable more than once at a time --> src/main.rs:6:14 | 5 | let r1 = &mut s; | ------ first mutable borrow occurs here 6 | let r2 = &mut s; | ^^^^^^ second mutable borrow occurs here 7 | 8 | println!("{}, {}", r1, r2); | -- first borrow later used here अंतिम शब्द उम्मीद है, यह स्वामित्व और उधार की अवधारणाओं को स्पष्ट करता है। मैंने उधार चेकर, स्वामित्व और उधार की रीढ़ की हड्डी पर भी संक्षेप में बात की। जैसा कि मैंने शुरुआत में उल्लेख किया है, स्वामित्व एक नया विचार है जिसे पहले समझना मुश्किल हो सकता है, यहां तक कि अनुभवी डेवलपर्स के लिए भी, लेकिन जितना अधिक आप इस पर काम करते हैं उतना आसान और आसान हो जाता है। यह रस्ट में स्मृति सुरक्षा को कैसे लागू किया जाता है, इसका एक संक्षिप्त विवरण है। मैंने अवधारणाओं को समझने के लिए पर्याप्त जानकारी प्रदान करते हुए इस पोस्ट को यथासंभव आसान बनाने का प्रयास किया। रस्ट की स्वामित्व विशेषता के बारे में अधिक जानकारी के लिए, उनके ऑनलाइन देखें। दस्तावेज़ जब प्रदर्शन मायने रखता है तो जंग एक बढ़िया विकल्प है और यह कई अन्य भाषाओं को परेशान करने वाले दर्द बिंदुओं को हल करता है, जिसके परिणामस्वरूप एक महत्वपूर्ण कदम आगे बढ़ने की अवस्था में होता है। लगातार छठे वर्ष, रही है, जिसका अर्थ है कि बहुत से लोग जिन्हें इसका उपयोग करने का मौका मिला है, उन्हें इससे प्यार हो गया है। जंग समुदाय का विकास जारी है। रस्ट स्टैक ओवरफ्लो की सबसे पसंदीदा भाषा : वर्ष 2021 निस्संदेह रस्ट के इतिहास में सबसे महत्वपूर्ण में से एक था। इसने रस्ट फाउंडेशन की स्थापना, 2021 संस्करण और पहले से कहीं अधिक बड़े समुदाय को देखा। जैसे ही हम भविष्य में आगे बढ़ते हैं, जंग एक मजबूत सड़क पर दिखाई देती है। रस्ट सर्वे 2021 के परिणाम के अनुसार हैप्पी लर्निंग!